package com.example.imgup;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.widget.OverScroller;
import android.widget.PopupMenu;
import android.widget.Toast;
import android.graphics.Rect;
import androidx.appcompat.widget.AppCompatImageView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ZoomImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener {
    private Rect currentRect;
    private int selectedRectIndex = -1;
    private boolean mIsOneLoad = true;

    // 初始化的比例，也就是最小比例
    private float mInitScale;
    // 图片最大比例
    private float mMaxScale;
    // 双击能达到的最大比例
    private float mMidScale;
    private Matrix mScaleMatrix;
    // 捕获用户多点触控
    private ScaleGestureDetector mScaleGestureDetector;
    // 移动
    private GestureDetector gestureDetector;
    // 双击
    private boolean isEnlarge = false; // 是否放大
    private ValueAnimator mAnimator; // 双击缩放动画
    // 滚动
    private OverScroller scroller;
    private int mCurrentX, mCurrentY;
    private ValueAnimator translationAnimation; // 惯性移动动画
    // 单击
    private OnClickListener onClickListener; // 单击监听
    // 标注
    private Paint annotationPaint;
    public List<Rect> annotations;
    private String selectedLabel;
    private String selectedText;
    private float mCurrentScale = 1.0f;
    private int mOriginalImageWidth;
    private int mOriginalImageHeight;
    private ArrayList<ArrayList<Object>> rectangleData = new ArrayList<>();
    private OnAnnotationsDrawnListener onAnnotationsDrawnListener;
    public void setOnAnnotationsDrawnListener(OnAnnotationsDrawnListener listener) {
        this.onAnnotationsDrawnListener = listener;
    }
    private void notifyAnnotationsDrawn() {
        if (onAnnotationsDrawnListener != null) {
            onAnnotationsDrawnListener.onAnnotationsDrawn();
        }
    }
    public interface OnAnnotationsDrawnListener {
        void onAnnotationsDrawn();
    }
    public ZoomImageView(Context context) {
        this(context, null);
    }

    public ZoomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 记住，一定要把ScaleType设置成ScaleType.MATRIX，否则无法缩放
        //setScaleType(ScaleType.MATRIX);
        setScaleType(ScaleType.FIT_CENTER);

        scroller = new OverScroller(context);
        mScaleMatrix = new Matrix();
        setImageMatrix(mScaleMatrix);
        selectedLabel = ""; // 初始化selectedLabel变量

        // 手势缩放
        mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                scale(detector);
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                scaleEnd(detector);
            }
        });

        // 滑动和双击监听
        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, final float distanceY) {
                // 滑动监听
                onTranslationImage(-distanceX, -distanceY);
                return true;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                // 双击监听
                //onDoubleDrowScale(e.getX(), e.getY());
                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

                // 滑动惯性处理
                mCurrentX = (int) e2.getX();
                mCurrentY = (int) e2.getY();

                RectF rectF = getMatrixRectF();
                if (rectF == null) {
                    return false;
                }
                // startX为当前图片左边界的x坐标
                int startX = mCurrentX;
                int startY = mCurrentY;
                int minX = 0, maxX = 0, minY = 0, maxY = 0;
                int vX = Math.round(velocityX);
                int vY = Math.round(velocityY);

                maxX = Math.round(rectF.width());
                maxY = Math.round(rectF.height());

                if (startX != maxX || startY != maxY) {
                    // 调用fling方法，然后我们可以通过调用getCurX和getCurY来获得当前的x和y坐标
                    // 这个坐标的计算是模拟一个惯性滑动来计算出来的，我们根据这个x和y的变化可以模拟
                    // 出图片的惯性滑动
                    scroller.fling(startX, startY, vX, vY, 0, maxX, 0, maxY, maxX, maxY);
                }

                if (translationAnimation != null && translationAnimation.isStarted())
                    translationAnimation.end();

                translationAnimation = ObjectAnimator.ofFloat(0, 1);
                translationAnimation.setDuration(500);
                translationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        if (scroller.computeScrollOffset()) {
                            // 获得当前的x坐标
                            int newX = scroller.getCurrX();
                            int dx = newX - mCurrentX;
                            mCurrentX = newX;
                            // 获得当前的y坐标
                            int newY = scroller.getCurrY();
                            int dy = newY - mCurrentY;
                            mCurrentY = newY;
                            // 进行平移操作
                            if (dx != 0 && dy != 0)
                                onTranslationImage(dx, dy);
                        }
                    }
                });
                translationAnimation.start();
                return super.onFling(e1, e2, velocityX, velocityY);
            }

            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                // 单击事件
                if (onClickListener != null)
                    onClickListener.onClick(ZoomImageView.this);
                return true;
            }
        });
        setClickable(true);

        // 初始化标注画笔
        annotationPaint = new Paint();
        annotationPaint.setColor(Color.RED);
        annotationPaint.setStyle(Paint.Style.STROKE);
        annotationPaint.setStrokeWidth(5);
        annotations = new ArrayList<>();
    }

    @Override
    public void setOnClickListener(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    /**
     * imageView加载完成后调用，获取imageView加载完成后的图片大小
     */
    @Override
    public void onGlobalLayout() {
        if (mIsOneLoad) {

            // 得到控件的宽和高
            int width = getWidth();
            int height = getHeight();

            // 获取图片,如果没有图片则直接退出
            Drawable d = getDrawable();
            if (d == null)
                return;

            // 获取图片的宽和高
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();

            float scale = Math.min((float) width / dw, (float) height / dh);

            // 根据宽度比例缩放图片高度
            int scaledHeight = Math.round(dh * scale);

            // 图片原始比例，图片回复原始大小时使用
            mInitScale = scale;
            // 存储原始图像尺寸
            mOriginalImageWidth = dw;
            mOriginalImageHeight = dh;
            // 图片双击后放大的比例
            mMidScale = mInitScale * 2;
            // 手势放大时最大比例
            mMaxScale = mInitScale * 4;
            // 计算缩放比例，使得图片能够完整显示在控件中心
            float scaleFactor = Math.min((float) width / dw, (float) height / dh);

            removeBorderAndTranslationCenter();
            mIsOneLoad = false;

            // 移除监听器
            ViewTreeObserver observer = getViewTreeObserver();
            if (observer.isAlive()) {
                observer.removeOnGlobalLayoutListener(this);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mScaleGestureDetector.onTouchEvent(event) |
                gestureDetector.onTouchEvent(event) |
                handleAnnotationTouchEvent(event);
    }

    // 手势操作（缩放）
    public void scale(ScaleGestureDetector detector) {

        Drawable drawable = getDrawable();
        if (drawable == null)
            return;

        float scale = getScale();
        // 获取手势操作的值,scaleFactor>1说明放大，<1则说明缩小
        float scaleFactor = detector.getScaleFactor();
        // 获取手势操作后的比例，当放操作后比例在[mInitScale,mMaxScale]区间时允许放大
        scale *= scaleFactor;
        scale = Math.max(mInitScale, Math.min(scale, mMaxScale));

        // 获取手势操作后的中心点坐标
        float focusX = detector.getFocusX();
        float focusY = detector.getFocusY();

        // 根据手势操作进行缩放
        mScaleMatrix.postScale(scale / getScale(), scale / getScale(), focusX, focusY);
        removeBorderAndTranslationCenter();
        setImageMatrix(mScaleMatrix);
    }

    // 手势操作结束
    public void scaleEnd(ScaleGestureDetector detector) {
        float scale = getScale();
        scale = Math.max(mInitScale, Math.min(scale, mMaxScale));

        // 如果缩放比例小于初始比例，则进行动画恢复到初始比例
        if (scale < mInitScale) {
            scaleAnimation(mInitScale, getWidth() / 2, getHeight() / 2);
        } else if (scale > mMaxScale) {
            scaleAnimation(mMaxScale, getWidth() / 2, getHeight() / 2);
        } else {
            removeBorderAndTranslationCenter();
        }
    }

    // 手势操作（移动）
    private void onTranslationImage(float dx, float dy) {

        if (getDrawable() == null)
            return;

        RectF rect = getMatrixRectF();

        // 图片宽度小于控件宽度时不允许左右移动
        if (rect.width() <= getWidth())
            dx = 0.0f;
        // 图片高度小于控件宽度时，不允许上下移动
        if (rect.height() <= getHeight())
            dy = 0.0f;

        // 移动距离等于0，那就不需要移动了
        if (dx == 0.0f && dy == 0.0f)
            return;

        mScaleMatrix.postTranslate(dx, dy);
        removeBorderAndTranslationCenter();
        setImageMatrix(mScaleMatrix);
    }

    // 消除控件边界和把图片移动到中间
    private void removeBorderAndTranslationCenter() {
        RectF rectF = getMatrixRectF();
        if (rectF == null)
            return;

        int width = getWidth();
        int height = getHeight();
        float widthF = rectF.width();
        float heightF = rectF.height();
        float left = rectF.left;
        float right = rectF.right;
        float top = rectF.top;
        float bottom = rectF.bottom;
        float translationX = 0.0f, translationY = 0.0f;

        if (left > 0) {
            // 左边有边界
            if (widthF > width) {
                // 图片宽度大于控件宽度，移动到左边贴边
                translationX = -left;
            } else {
                // 图片宽度小于控件宽度，移动到中间
                translationX = width * 1.0f / 2f - (widthF * 1.0f / 2f + left);
            }
        } else if (right < width) {
            // 右边有边界
            if (widthF > width) {
                // 图片宽度大于控件宽度，移动到右边贴边
                translationX = width - right;
            } else {
                // 图片宽度小于控件宽度，移动到中间
                translationX = width * 1.0f / 2f - (widthF * 1.0f / 2f + left);
            }
        }

        if (top > 0) {
            // 顶部有边界
            if (heightF > height) {
                // 图片高度大于控件高度，去除顶部边界
                translationY = -top;
            } else {
                // 图片高度小于控件宽度，移动到中间
                translationY = height * 1.0f / 2f - (top + heightF * 1.0f / 2f);
            }
        } else if (bottom < height) {
            // 底部有边界
            if (heightF > height) {
                // 图片高度大于控件高度，去除顶部边界
                translationY = height - bottom;
            } else {
                // 图片高度小于控件宽度，移动到中间
                translationY = height * 1.0f / 2f - (top + heightF * 1.0f / 2f);
            }
        }

        mScaleMatrix.postTranslate(translationX, translationY);
        setImageMatrix(mScaleMatrix);
    }

    /**
     * 缩放动画
     *
     * @param drowScale 缩放的比例
     * @param x         中心点
     * @param y         中心点
     */
    private void scaleAnimation(final float drowScale, final float x, final float y) {
        if (mAnimator != null && mAnimator.isRunning())
            return;
        mAnimator = ObjectAnimator.ofFloat(getScale(), drowScale);
        mAnimator.setDuration(300);
        mAnimator.setInterpolator(new AccelerateInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = ((float) animation.getAnimatedValue()) / getScale();
                mScaleMatrix.postScale(value, value, x, y);
                setImageMatrix(mScaleMatrix);
                removeBorderAndTranslationCenter();
            }
        });

        mAnimator.start();
    }
    // 获取图片宽高以及左右上下边界
    public RectF getMatrixRectF() {

        Drawable drawable = getDrawable();
        if (drawable == null) {
            return null;
        }
        RectF rectF = new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        Matrix matrix = getImageMatrix();
        matrix.mapRect(rectF);

        return rectF;
    }


    /**
     * 获取当前图片的缩放值
     *
     * @return
     */
    private float getScale() {
        float[] values = new float[9];
        mScaleMatrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }


    /**
     * 解决和父控件滑动冲突 只要图片边界超过控件边界，返回true
     *
     * @param direction
     * @return true 禁止父控件滑动
     */
    @Override
    public boolean canScrollHorizontally(int direction) {
        RectF rect = getMatrixRectF();
        if (rect == null || rect.isEmpty())
            return false;

        if (direction > 0) {
            return rect.right >= getWidth() + 1;
        } else {
            return rect.left <= 0 - 1;
        }

    }

    /**
     * 同楼上
     *
     * @param direction
     * @return
     */
    @Override
    public boolean canScrollVertically(int direction) {
        RectF rect = getMatrixRectF();
        if (rect == null || rect.isEmpty())
            return false;

        if (direction > 0) {
            return rect.bottom >= getHeight() + 1;
        } else {
            return rect.top <= 0 - 1;
        }
    }

    // 处理标注的触摸事件
    private boolean isDrawing = false;
    private boolean handleAnnotationTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                currentRect = new Rect();
                currentRect.left = (int) x;
                currentRect.top = (int) y;
                currentRect.right = (int) x;
                currentRect.bottom = (int) y;
                isDrawing = true;
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                if (isDrawing) {
                    currentRect.right = (int) x;
                    currentRect.bottom = (int) y;
                    invalidate();
                }
                break;
            // 在ACTION_UP事件中设置selectedRectIndex的值
            case MotionEvent.ACTION_UP:
                if (isDrawing) {
                    annotations.add(currentRect);
                    selectedRectIndex = annotations.size() - 1;
                    isDrawing = false;
                    showLabelDropdown(currentRect.left, currentRect.top); // 在矩形框的左上角显示下拉菜单
                    // 在这里调用 updateLabelList 方法，并传入选中的文字和索引
                    updateLabelList(selectedRectIndex, selectedLabel); // 此处传递选中的标签和索引
                    invalidate();
                    // 在这里通知标注框绘制完成
                    notifyAnnotationsDrawn();
                }
                break;
        }

        return true;
    }


    // 在你的类中添加一个用于存储标注框文字的集合
    List<String> labelList = new ArrayList<>();
    // 修改onDraw方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        for (int i = 0; i < annotations.size(); i++) {
            Rect rect = annotations.get(i);
            canvas.drawRect(rect, annotationPaint);
            // 根据缩放比例调整标注框的坐标和大小
            rect.left *= mCurrentScale;
            rect.top *= mCurrentScale;
            rect.right *= mCurrentScale;
            rect.bottom *= mCurrentScale;

            // 检查是否有对应的标签
            if (i < labelList.size()&& labelList.get(i) != null) {
                String label = labelList.get(i);

                Paint textPaint = new Paint();
                textPaint.setColor(Color.RED);
                textPaint.setTextSize(30);

                // 计算文字的绘制位置，左上角靠近标注框内
                float textX = rect.left;
                float textY = rect.top - 10;
                // 计算标注框的中心坐标
                float centerX = (rect.left + rect.right) / 2;
                float centerY = (rect.top + rect.bottom) / 2;

                // 计算标注框的相对宽度和高度
                float relativeWidth = (rect.right - rect.left) / mOriginalImageWidth;
                float relativeHeight = (rect.bottom - rect.top) / mOriginalImageHeight;

                // 创建一个保存矩形框信息的列表
                ArrayList<Object> rectangleInfo = new ArrayList<>();
                rectangleInfo.add(label);
                rectangleInfo.add(centerX);
                rectangleInfo.add(centerY);
                rectangleInfo.add(relativeWidth);
                rectangleInfo.add(relativeHeight);

                // 将矩形框信息添加到二维数组中
                if (i < rectangleData.size()) {
                    rectangleData.set(i, rectangleInfo);
                } else {
                    rectangleData.add(rectangleInfo);
                }

                canvas.drawText(label, textX, textY, textPaint);
            }else {
                Log.e("ZoomImageView", "Label at index " + i + " is null");
            }
        }
    }
    public ArrayList<ArrayList<Object>> getRectangleData() {
        return rectangleData;
    }
    private void updateLabelList(int rectIndex, String label) {
        // 更新或添加标签
        if (rectIndex < labelList.size()) {
            labelList.set(rectIndex, label);
        } else {
            labelList.add(label);
        }
        // 更新或添加矩形框信息
        ArrayList<Object> rectangleInfo = new ArrayList<>();
        if (rectIndex < rectangleData.size()) {
            rectangleInfo = rectangleData.get(rectIndex);
        }
        // 在这里添加标签、中心坐标、相对宽度和相对高度到rectangleInfo
        if (rectIndex < rectangleData.size()) {
            rectangleData.set(rectIndex, rectangleInfo);
        } else {
            rectangleData.add(rectangleInfo);
        }
        // 触发重绘
        invalidate();
    }
    public List<Rect> getAnnotations() {
        return annotations;
    }
    private void showLabelDropdown(float x, float y) {
        // 创建一个有序的标签列表
        List<String> sortedLabels = new ArrayList<>();
        sortedLabels.add("狗");
        sortedLabels.add("猫");
        sortedLabels.add("人");
        sortedLabels.add("汽车");
        sortedLabels.add("书");
        sortedLabels.add("椅子");
        sortedLabels.add("杯子");
        sortedLabels.add("电脑");
        // 导出标签到文件示例
        ExportLabelsToFile.exportLabelsToFile(sortedLabels, getContext());
        // 对标签列表进行排序
        Collections.sort(sortedLabels);

        // 创建一个PopupMenu对象
        PopupMenu popupMenu = new PopupMenu(getContext(), this, Gravity.NO_GRAVITY, androidx.appcompat.R.attr.actionOverflowMenuStyle, 0);

        // 添加排序后的菜单项
        for (String label : sortedLabels) {
            popupMenu.getMenu().add(label);
        }

        // 设置菜单项点击事件
        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                // 获取用户选择的词语
                selectedLabel = item.getTitle().toString();
                // 调用updateLabelList方法，在这里传入选中的文字
                updateLabelList(selectedRectIndex, selectedLabel);
                // 执行相应操作，例如显示Toast
                Toast.makeText(getContext(), "选择的词语：" + selectedLabel, Toast.LENGTH_SHORT).show();
                return true;
            }
        });

        // 显示下拉菜单
        popupMenu.show();
    }

    public String getSelectedLabel() {
        return selectedLabel;
    }
    //清除文字
    public void clearSelectedText() {
        selectedText = null;
        invalidate(); // 重绘视图
    }
    public void undoLastAnnotation() {
        List<Rect> annotations = getAnnotations();
        if (!annotations.isEmpty()) {
            annotations.remove(annotations.size() - 1);
            selectedRectIndex = annotations.size() - 1; // 更新selectedRectIndex的值
            invalidate(); // 重绘视图
        }
        clearSelectedText(); // 清除选择的文字
    }
    public void clearAnnotations() {
        annotations.clear(); // 清空标注框的集合
        labelList.clear(); // 清空标注框文字的集合
        rectangleData.clear(); // 清空二维数组的内容
        selectedRectIndex = -1; // 重置选中的标注框索引
        selectedLabel = null; // 重置选中的标签
        invalidate(); // 重新绘制视图
    }
}